package com.xhui.vimarket.common.utils.collection.impl;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xhui.vimarket.common.utils.collection.VimarketSet;

public class VimarketHashSet<E> extends HashSet<E> implements VimarketSet<E> {

    /**
     * 日志记录器。
     */
    private static final Logger LOG = LoggerFactory.getLogger(VimarketHashSet.class);
//    private final Class<E> elementClass = 
//        (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    
    /**
     * 版本序列号。
     */
    private static final long serialVersionUID = -8060978548341643766L;
    /**
     * 空对象。
     */
    protected static final Object PRESENT = new Object();
    
    /**
     * 是否初始化完成。
     */
    private boolean isInitialCompleted;
    /**
     * 初始化后所添加元素的集合。
     */
    private transient HashMap<E, Object> additionMap;
    /**
     * 从初始列表中删除元素的集合。
     */
    private transient HashMap<E, Object> deletionMap;
    /**
     * 从初始列表中更新元素的集合。
     */
    private transient HashMap<E, Object> updationMap;
    
    /**
     * 默认构造函数。
     */
    public VimarketHashSet() {
        this.additionMap = new HashMap<E, Object>();
        this.deletionMap = new HashMap<E, Object>();
        this.updationMap = new HashMap<E, Object>();
        this.isInitialCompleted = true;
    }
    
    /**
     * 根据初始集合，初始化Set。
     * 
     */
    public VimarketHashSet(Collection<? extends E> c) {
        super(c);
        this.additionMap = new HashMap<E, Object>();
        this.deletionMap = new HashMap<E, Object>();
        this.updationMap = new HashMap<E, Object>();
        this.isInitialCompleted = true;
    }
    
    /**
     * 根据初始集合的大小，初始化Set。
     * 
     */
    public VimarketHashSet(int initialCapacity) {
        super(initialCapacity);
        this.additionMap = new HashMap<E, Object>();
        this.deletionMap = new HashMap<E, Object>();
        this.updationMap = new HashMap<E, Object>();
        this.isInitialCompleted = true;
    }
    
    /**
     * 根据初始集合大小和增量因子，初始化Set。
     * 
     */
    public VimarketHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        this.additionMap = new HashMap<E, Object>();
        this.deletionMap = new HashMap<E, Object>();
        this.updationMap = new HashMap<E, Object>();
        this.isInitialCompleted = true;
    }
    
    /**
     */
    @Override
    public Iterator<E> iterator() {
        return new CompositeIterator<E>(super.iterator(), this.additionMap.keySet().iterator());
//        {
//            /**
//             * {@inheritDoc}
//             * @see com.xhui.crm.common.util.collection.impl.CompositeIterator#checkForComodification()
//             * @author 吴兆彬
//             * 2011-1-27 吴兆彬
//             */
//            @Override
//            protected void checkForComodification() {
//                if (CrmHashSet.super.size() != this.expectedRetainCount 
//                    || CrmHashSet.this.additionMap.size() != this.expectedAdditionCount) {
//                    throw new ConcurrentModificationException();
//                }
//            }
//        };
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public int size() {
        return super.size() + this.additionMap.size();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isEmpty() {
        return super.isEmpty() && this.additionMap.isEmpty();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean contains(Object o) {
        return super.contains(o) || this.additionMap.containsKey(o);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean addInitial(E e) {
        return super.add(e);
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean addInitial(Collection<? extends E> c) {
        this.isInitialCompleted = false;
        boolean result = super.addAll(c);
        this.isInitialCompleted = true;
        return result;
    }
    
    /**
     * {@inheritDoc}
     */
    public boolean removeDirectly(E e) {
        return this.removeInternal(e, false);
    }

    /**
     * {@inheritDoc}
     * 
     * 顺序执行以下步骤：
     * 1. 先判断是否该元素存在于“deletionMap”中；
     * 2. 如果存在，则从“deletionMap”中删除该元素，并在“map”中添加该元素，并将该元素添加到更新列表；
     * 3. 如果不存在，则直接添加到“additionMap”中。
     * 
     */
    @Override
    public boolean add(E e) {
        if (this.isInitialCompleted) {
            if (this.deletionMap.containsKey(e)) {
                Iterator<E> iterator = this.deletionMap.keySet().iterator();
                e = this.getObjectFromIterator(iterator, e);
                this.deletionMap.remove(e);
                this.updationMap.put(e, PRESENT);
                return super.add(e);
            } else {
                return (this.additionMap.put(e, PRESENT) == null);
            }
        } else {
            return super.add(e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void update(E element) {
        if (super.contains(element) && !this.updationMap.containsKey(element)) {
            this.updationMap.put(element, PRESENT);
        }
    }
    
    /**
     * 从迭代中获取某个元素。
     * 
     */
    protected E getObjectFromIterator(Iterator<E> iterator, Object e) {
        E next = null;
        if (e == null) {
            while (iterator.hasNext()) {
                if (iterator.next() == null) {
                    return null;
                }
            }
        } else {
            while (iterator.hasNext()) {
                next = iterator.next();
                if (e.equals(next)) {
                    return next;
                }
            }
        }
        return null;
    }

    /**
     * {@inheritDoc}
     * 
     * 顺序执行以下步骤：
     * 1. 先判断该元素是否存在于“additionMap”中；
     * 2. 如果存在，则直接从“additionMap”中删除；
     * 3. 如果不存在，则从“map”中删除该元素，并在“deletionMap”中添加该元素，并从更新列表中删除。
     * 
     */
    @Override
    public boolean remove(Object o) {
        return this.removeInternal(o, true);
    }
    
    /**
     * 删除元素，根据标识位判断是否要移动到deletionMap。
     * 
     */
    @SuppressWarnings("unchecked")
    private boolean removeInternal(Object o, boolean isAddToDeletionData) {
        if (this.additionMap.containsKey(o)) {
            return (this.additionMap.remove(o) == PRESENT);
        } else {
            o = this.getObjectFromIterator(super.iterator(), o);
            boolean result = super.remove(o);
            if (result) {
                if (this.updationMap.containsKey(o)) {
                    this.updationMap.remove(o);
                }
                if (isAddToDeletionData) {
                    this.deletionMap.put((E) o, PRESENT);
                }
            }
            return result;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean removeAll(Collection<?> c) {
        boolean modified = false;
        if (size() > c.size()) {
            for (Iterator<?> i = c.iterator(); i.hasNext();) {
                modified |= remove(i.next());
            }
        } else {
            Iterator<E> i;
            E item;
            for (i = super.iterator(); i.hasNext();) { // 初始集合
                item = i.next();
                if (c.contains(item)) {
                    i.remove();
//                    if (super.remove(item)) {
                        if (this.updationMap.containsKey(item)) {
                            this.updationMap.remove(item);
                        }
                        this.deletionMap.put(item, PRESENT);
                        modified = true;
//                    }
                }
            }
            for (i = this.additionMap.keySet().iterator(); i.hasNext();) { // 新增集合
                if (c.contains(i.next())) {
                    i.remove();
                    modified = true;
                }
            }
        }
        return modified;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean retainAll(Collection<?> c) {
        boolean modified = false;
        Iterator<E> i;
        E item;
        for (i = super.iterator(); i.hasNext();) {
            item = i.next();
            if (!c.contains(item)) {
                if (super.remove(item)) {
                    if (this.updationMap.containsKey(item)) {
                        this.updationMap.remove(item);
                    }
                    this.deletionMap.put(item, PRESENT);
                    modified = true;
                }
            }
        }
        for (i = this.additionMap.keySet().iterator(); i.hasNext();) {
            if (!c.contains(i.next())) {
                i.remove();
                modified = true;
            }
        }
        return modified;
    }
    
    /**
     * {@inheritDoc}
     * 
     * 执行以下清空操作：
     * 1. 将“map”所有元素添加到“deletionMap”中，并从“map”中删除；
     * 2. 清空“additionMap”；
     * 
     */
    @Override
    public void removeAll() {
        // DeletionData和InitialData
        Iterator<E> iterator = super.iterator();
        E item;
        while (iterator.hasNext()) {
            item = iterator.next();
            this.deletionMap.put(item, PRESENT);
            iterator.remove();
        }
        // UpdationData
        this.updationMap.clear();
        // AdditionData
        this.additionMap.clear();
    }
    
    /**
     * {@inheritDoc}
     * 
     * 清空所有数据。
     * 
     * @see java.util.HashSet#clear()
     * @author 吴兆彬
     * 2011-7-8 吴兆彬
     */
    @Override
    public void clear() {
        // 删除DeletionData
        this.deletionMap.clear();
        // 删除updationData
        this.updationMap.clear();
        // 删除InitialData和AdditionData
        super.clear();
        this.additionMap.clear();
    }
    
    /**
     * {@inheritDoc}
     */
    public void initialAllData() {
        // 删除DeletionData
        this.deletionMap.clear();
        
        // 删除updationData
        this.updationMap.clear();
        
        // 将“新增数据”转移到“初始数据”
        Iterator<E> iterator = this.additionMap.keySet().iterator();
        E item;
        while (iterator.hasNext()) {
            item = iterator.next();
            super.add(item);
            iterator.remove();
        }
//        this.isInitialCompleted = false;
//        super.addAll(this.additionMap.keySet());
//        this.isInitialCompleted = true;
        
        this.additionMap.clear();
    }
    /**
     * {@inheritDoc}
     */
    public void restoreAllData() {
        //删除新增数据
        this.additionMap.clear();
        //删除数据还原
        this.addAll(this.deletionMap.keySet());
        // 删除DeletionData
        this.deletionMap.clear();
        
        // 删除updationData
        this.updationMap.clear();
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public Object clone() {
    	VimarketHashSet<E> newSet = (VimarketHashSet<E>) super.clone();
        newSet.additionMap = (HashMap<E, Object>) additionMap.clone();
        newSet.deletionMap = (HashMap<E, Object>) deletionMap.clone();
        newSet.updationMap = (HashMap<E, Object>) updationMap.clone();
        return newSet;
    }
    
    /**
     */
    @Override
    public Set<E> getAdds() {
//        E[] r = (E[]) Array.newInstance(elementClass, this.additionMap.size());
//        return this.additionMap.keySet().toArray(r);
        return this.additionMap.keySet();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getAddsIterator() {
        return this.additionMap.keySet().iterator();
    }
    
    /**
     * {@inheritDoc}
     * @see com.xhui.crm.common.util.collection.CrmSet#getAll()
     * @author 吴兆彬
     * 2011-1-27 吴兆彬
     */
    @Override
    public Set<E> getAll() {
//        E[] r = (E[]) Array.newInstance(elementClass, this.size());
//        return this.toArray(r);
        Set<E> set = new HashSet<E>();
        set.addAll(this);
        return set;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getAllIterator() {
        return this.iterator();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Set<E> getRemoves() {
//        E[] r = (E[]) Array.newInstance(elementClass, this.deletionMap.size());
//        return this.deletionMap.keySet().toArray(r);
        return this.deletionMap.keySet();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getRemovesIterator() {
        return this.deletionMap.keySet().iterator();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Set<E> getRetains() {
        Set<E> set = new HashSet<E>();
        Iterator<? extends E> iterator = super.iterator();
        while (iterator.hasNext()) {
            set.add(iterator.next());
        }
        return set;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getRetainsIterator() {
        return super.iterator();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Set<E> getUpdates() {
//      E[] r = (E[]) Array.newInstance(elementClass, this.updationMap.size());
//      return this.updationMap.keySet().toArray(r);
      return this.updationMap.keySet();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getUpdatesIterator() {
        return this.updationMap.keySet().iterator();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Set<E> getInitials() {
        Set<E> set = new HashSet<E>();
        Iterator<? extends E> iterator = super.iterator();
        E e;
        while (iterator.hasNext()) {
            e = iterator.next();
            if (!this.updationMap.containsKey(e)) {
                set.add(e);
            }
        }
        return set;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getInitialsIterator() {
        return this.getInitials().iterator();
    }

    @Override
    public Set<E> getCollectionByProperty(String propertyName, Object propertyValue) {
        Set<E> set = new HashSet<E>();
        E item;
        Object value;
        Iterator<E> iterator = this.iterator();
        while (iterator.hasNext()) {
            item = iterator.next();
            try {
                value = PropertyUtils.getProperty(item, propertyName);
            } catch (Exception e) {
                LOG.info("Not such property “" + propertyName + "” in CrmArrayList.");
                break;
            }
            if (propertyValue == null) {
                if (value == null) {
                    set.add(item);
                }
            } else {
                if (propertyValue.equals(value)) {
                    set.add(item);
                }
            }
        }
        return set;
    }

    @Override
    public E getByProperty(String propertyName, Object propertyValue) {
        E item = null;
        Object value;
        Iterator<E> iterator = this.iterator();
        while (iterator.hasNext()) {
            item = iterator.next();
            try {
                value = PropertyUtils.getProperty(item, propertyName);
            } catch (Exception e) {
                LOG.info("Not such property “" + propertyName + "” in CrmArrayList.");
                break;
            }
            if (propertyValue == null) {
                if (value == null) {
                    return item;
                }
            } else {
                if (propertyValue.equals(value)) {
                    return item;
                }
            }
        }
        return null;
    }
}
